package crypto.process;

import crypto.reference.References;
import crypto.util.RandomCrypto;
/**
 * DOCUMENT ME!
 *
 * @author gato
 */
public class Matrix {
  private char   bin0             = '0';
  private char   bin1             = '1';
  private String binaryMapReduced;
  private int positionMapStart;
  private int positionMapEnd;

  /**
   * Metodo que toma el texto ingresado y lo expresa en un mapa de bits equivalente
   * dependiendo si los caracteres son mayusculas u otros.
   *
   * @param textMap [String]
   *
   * @return Mapa de bits Reducido [String]
   */
  public String mapBitsMayus(String textMap) {
    String binMap                 = "";
    char[] map                    = textMap.toCharArray();

    for (int i = 0; i < map.length; i++) {
      if ((map[i] < 91) && (map[i] > 64)) {
        binMap += ("" + bin1);
      } else {
        binMap += ("" + bin0);
      }
    }

    binaryMapReduced = this.reduceMap(binMap, 0);
    
    positionMapStart = RandomCrypto.getRandomInt( textMap.length()+1 );
    positionMapEnd = positionMapStart + binaryMapReduced.length();
    
    textMap = textMap.substring(0, positionMapStart ) + binaryMapReduced + textMap.substring( positionMapStart );

    return textMap.toUpperCase();
  }

  /**
   * Metodo que reduce la cadena de bits contando la cantidad de veces que se repite cada
   * bits que esten consecutivos.
   *
   * @param mp de bits [String]
   * @param pos de inicio de la comparacion [Integer]
   *
   * @return Cadena Reducida [String]
   */
  private String reduceMap(String mp, int pos) {
    String letter;
    char   symbol;

    if (mp.length() == 0)
      return "";

    char[] mapBinary = mp.toCharArray();

    if (mapBinary[pos] == bin1) {
      symbol   = bin1;
      letter   = "Z";
    } else {
      symbol   = bin0;
      letter   = "Y";
    }

    int cant = 0;

    while ((pos < mapBinary.length) && (mapBinary[pos] == symbol)) {
      cant++;
      pos++;
    }

    if (pos == mapBinary.length) {
      if (cant > 1) {
        return (cant + letter);
      }

      return letter;
    } else {
      if (cant > 1) {
        return (cant + letter) + reduceMap(mp, pos);
      }

      return letter + reduceMap(mp, pos);
    }
  }

  /**
   * Metodo que toma como entrada la cadena de bits reducida y la expande hasta formar la
   * respectiva cadena conteniendo solo 1 y 0.
   *
   * @param map de Bits Reducido [String]
   *
   * @return Mapa de Bits Expandido [String]
   */
  public String expandMapBits(String map) {
    if (map.length() == 0) {
      return "";
    }

    int    numZ   = map.indexOf("Z");
    int    numY   = map.indexOf("Y");
    int    num    = 0;
    String symbol;

    if (((numZ < numY) || (numY == -1)) && (numZ > -1)) {
      num         = numZ;
      symbol      = "1";
    } else {
      num      = numY;
      symbol   = "0";
    }

    int cant = 1;

    if (num != 0) {
      cant = Integer.parseInt(map.substring(0, num));
    }

    String result = "";

    for (int i = 0; i < cant; i++) {
      result += symbol;
    }

    return result + expandMapBits(map.substring(num + 1));
  }

  /**
   * DOCUMENT ME!
   *
   * @param text DOCUMENT ME!
   * @param map DOCUMENT ME!
   *
   * @return DOCUMENT ME!
   */
  public String textNormalCase(String text, String map) {
    char[] arrayMap  = map.toCharArray();
    char[] arrayText = text.toCharArray();

    for (int i = 0; i < arrayMap.length; i++) {
      if (((arrayText[i] > 64) && (arrayText[i] < 91)) && (arrayMap[i] == 48)) {
        arrayText[i] += 32;
      }
    }

    return new String(arrayText);
  }
  
    public String textNormalCase(String text, References reference) {
        
        int positions[] = reference.getMatrixPositions();
        String map = text.substring( positions[0] , positions[1] );
        text = text.substring(0, positions[0]) + text.substring( positions[1] );
        String mapExpanded = this.expandMapBits(map);
        
        return this.textNormalCase(text, mapExpanded);
    }

    public int[] getPositionMap() {
        int positions[] = { positionMapStart, positionMapEnd };
        
        return positions;
    }

}
